import type { ComponentStyleIdType } from '../../types/interfaces'
import type { SelectProps } from './types'
import { UIComponent } from '../../lib/abstract'
import { ComponentStyleId } from '../../types/constants'
import { styles } from './styles'
import { DEFAULT_SELECT_PROPS } from './types'

export class Select extends UIComponent<SelectProps> {
  id: string = 'select'
  readonly description: string = '下拉框'
  readonly styleId: string = ComponentStyleId[this.name]
  // 用于递归检测
  private isSettingValue = false

  get name(): ComponentStyleIdType {
    return 'Select'
  }

  get className(): string {
    return 'custom-select'
  }

  constructor(props: SelectProps) {
    super({
      ...DEFAULT_SELECT_PROPS,
      ...props,
    })

    // 注册样式
    this.registerStyles()
  }

  ELEMENT_SELECTORS = {
    select: { selector: `#${this.props.id}`, dynamic: false, unique: true },
    clearBtn: { selector: '.clear-btn', dynamic: false, unique: false },
  }

  /**
   * 设置选择值
   */
  setValue(value: string): void {
    if (this.isSettingValue)
      return

    this.isSettingValue = true

    try {
      const $select = this.getElement('select')

      if (!$select || !$select.length)
        return

      $select.val(value).trigger('change')
    }
    finally {
      this.isSettingValue = false
    }
  }

  getValue(): string | undefined {
    const $select = this.getElement('select')

    if (!$select) {
      return undefined
    }

    const value = $select.val() as string

    return value === '' ? undefined : value
  }

  render(): string {
    const { id, label, labelTextPosition, title, options, selectedValue, clearable, showPlaceholder, placeholder } = this.props as SelectProps

    return `
      <div class="${this.className}">
        ${label ? `<label for="${id}" style="text-align: ${labelTextPosition};" ${title ? `title="${title.replace(/\n/g, '&#10;')}"` : ''}>${label}</label>` : ''}
        <select id="${id}" class="${clearable ? '' : 'no-clear'}">
          ${showPlaceholder ? `<option value="" ${!selectedValue ? 'selected' : ''}>${placeholder}</option>` : ''}
          ${options.map(opt =>
            `
              <option value="${opt.value}" ${selectedValue && selectedValue === opt.value ? 'selected' : ''} ${opt.disabled ? 'disabled' : ''}>
                ${opt.label}
              </option>
            `,
          ).join('')}
        </select>
        ${clearable
          ? `
        <button class="clear-btn" ${selectedValue ? '' : 'disabled'}>
          <svg viewBox="0 0 24 24" width="16" height="16">
            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
          </svg>
        </button>
        `
          : ''}
      </div>
    `
  }

  bindEvents(): void {
    const { clearable, onInit, onChange } = this.props as SelectProps
    const $select = this.getElement('select')
    const $clearBtn = this.getElement('clearBtn')

    if ($select && $select.length && onChange) {
      $select.on('change', (e) => {
        const $el = $(e.currentTarget as HTMLInputElement)
        const value = $el.val() as string

        if (clearable) {
          this.getElement('clearBtn')?.prop('disabled', value === '')
        }

        onChange?.(value === '' ? undefined : value)
      })
    }

    if (clearable && $clearBtn && $clearBtn.length) {
      $clearBtn.on('click', (e) => {
        e.preventDefault()
        e.stopPropagation()

        this.getElement('select')?.val('').trigger('change')
      })
    }

    onInit?.(this)
  }

  getStyles(): string {
    return styles(this.className)
  }

  reset(): void {
    super.reset()

    // 重置下拉框值
    this.getElement('select')?.val('').trigger('change')
  }

  destroy(): void {
    super.destroy()
  }
}
